<?php
/**
 * Date: 2024.8
 * Author: kahn
 * 系统全局工具函数
 * 在bootstrap里引入
 */
use config\Response;
use JetBrains\PhpStorm\NoReturn;
use config\Common;

const ENCRYPT_KEY = 'General.2021022';
const ENCRYPT_IV = '63ssa6d5f4Xzhf&797d4f.g$t96bae20';

const GCommon = new Common();
/**
 * 输出变量的内容，通常用于调试
 *
 * @param mixed $vars 要输出的变量
 * @param string $label
 * @param boolean $return
 * @package Core
 *
 */
function dump($vars, $label = '', $return = false)
{
    if (ini_get('html_errors')) {
        $content = "<pre>\n";
        if ($label != '') {
            $content .= "<strong>{$label} :</strong>\n";
        }
        $content .= htmlspecialchars(print_r($vars, true));
        $content .= "\n</pre>\n";
    } else {
        $content = $label . " :\n" . print_r($vars, true);
    }
    if ($return) {
        return $content;
    }
    echo $content;
    return null;
}

function json($vars = [], $format = 'json', $callback = 'callback')
{
    if ($format == 'json') {
        header("Content-type: application/json;charset=utf-8");
        $data = updateNull($vars);
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
    } else {
        header("Content-type: text/javascript;charset=utf-8");
        $data = updateNull($vars);
        echo "{$callback}(" . json_encode($data, JSON_UNESCAPED_UNICODE) . ")";
    }
}

function jsonp($data, int $code = 200)
{
    http_response_code($code);
    if ($code != 200) {
        $data = ['msg' => $data];
    }
    json($data);
}

#[NoReturn] function response($code, $data=null): void
{
    header('Content-type: application/json; charset=utf-8');
    header('X-Powered-By: tomcat');
    header('Server: yahaha');
    $res['code'] = $code;
    $res['msg'] = Response::CODE_MSG[$code];
    $res['time'] = CURR_TIME;
    if($data !== null){
        $res['data'] = $data;
    }
    $json = json_encode($res, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES);;
    echo str_replace(':null,',':"",',$json);
    exit;
}

function updateNull(&$onearr)
{
    if (!empty($onearr) && is_array($onearr)) {
        foreach ($onearr as $k => $v) {
            if (is_array($v)) {
                $onearr[$k] = updateNull($v);
            } else {
                if ($v === NULL) {
                    $onearr[$k] = '';
                }
            }
        }
    }
    return $onearr;
}

#获取请求头
function getHeader($key=''){
    if($key=='') {
        $headers = [];
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_') {
                $headers[strtolower(substr($name, 5))] = $value;
            }
        }
        return $headers;
    }else{
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_' && strtolower($key)==strtolower(substr($name, 5))) {
                return $value;
            }
        }
    }
}

/***PHP上传文件到七牛cdn***/
function uploadToCDN($filePath, $cdnfileName)
{
    // 需要填写你的 Access Key 和 Secret Key
    $accessKey = Yaf_Registry::get('config')->application->cdn->accessKey;
    $secretKey = Yaf_Registry::get('config')->application->cdn->secretKey;

    // 构建鉴权对象
    $auth = new \Qiniu\Auth($accessKey, $secretKey);
    // 要上传的空间
    $bucket = Yaf_Registry::get('config')->application->cdn->bucket;

    // 生成上传 Token
    $token = $auth->uploadToken($bucket);

    // 上传到七牛后保存的文件名
    $key = $cdnfileName;

    // 初始化 UploadManager 对象并进行文件的上传
    $uploadMgr = new \Qiniu\Storage\UploadManager;

    // 调用 UploadManager 的 putFile 方法进行文件的上传
    [$ret, $err] = $uploadMgr->putFile($token, $key, $filePath);
    if ($err !== null) {
        return false;
    } else {
        return Yaf_Registry::get('config')->application->cdn->url . $ret['key'];
    }
}
function getClientIP(){
    $ip = 'unknow';
    $list = array(
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED',
        'HTTP_X_CLUSTER_CLIENT_IP',
        'HTTP_CLIENT_IP',
        'REMOTE_ADDR');
    foreach ($list as $key) {
        if (array_key_exists($key, $_SERVER)) {
            foreach (explode(',', $_SERVER[$key]) as $ip) {
                $ip = trim($ip);
                //会过滤掉保留地址和私有地址段的IP，例如 127.0.0.1会被过滤
                if ((bool)filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    return $ip;
                }
            }
        }
    }
    if ($ip == '::1'){
        $ip = '127.0.0.1';
    }
    return $ip;
}

/**
 * PHP生成随机字符串
 * @param int $length
 * @param int $type [0:全类型 1:数字 2:小写字母 3:大写字母]
 * @return string
 */
function randStr($length = 10, $type = 0): string
{
    switch ($type) {
        case 1:
            $characters = '1234567890';
            break;
        case 2:
            $characters = 'abcdefghijkmnopqrstuvwxyz';
            break;
        case 3:
            $characters = 'ABCDEFGHIJKLMNPOQRSTUVWXYZ';
            break;
        default:
            $characters = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ';
            break;
    }
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}

/**
 * 跳转
 *
 * @param      $url
 * @param null $headers
 */
function redirect($url)
{
    echo "<script>top.location.href='{$url}';</script>";
    exit;
}

function pick(string $url, $postData = '')
{
    $row  = parse_url($url);
    $host = $row['host'];
    $port = isset($row['port']) ? $row['port'] : 80;
    $file = $row['path'];
    if (is_array($postData)) {
        $postData = http_build_query($postData);
    }
    $len = strlen($postData);
    $fp  = @fsockopen($host, $port, $errno, $errstr, 10);
    if (!$fp) {
        return "$errstr ($errno)\n";
    } else {
        $receive = '';
        $out     = "POST $file HTTP/1.1\r\n";
        $out     .= "Host: $host\r\n";
        $out     .= "Content-type: application/x-www-form-urlencoded\r\n";
        $out     .= "Connection: Close\r\n";
        $out     .= "Content-Length: $len\r\n\r\n";
        $out     .= $postData;
        fwrite($fp, $out);
        while (!feof($fp)) {
            $receive .= fgets($fp, 128);
        }
        fclose($fp);
        $receive = explode("\r\n\r\n", $receive);
        unset($receive[0]);
        return implode("", $receive);
    }
}

/**
 * @param $url
 * @param $data
 * @param string $type
 * @param int $timeout
 * @param $referer
 * @return bool|string
 */
function httpRequest($url, $data = null, string $type='POST', int $timeout=5, $referer=null): bool|string
{
    $ch = curl_init();
    if ($data) {
        if(is_array($data)){
            $data = http_build_query($data,"","&");
        }
        if($type=='POST'){
            curl_setopt($ch,CURLOPT_POST,1);
            curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
        }else{
            $url .= strpos($url, '?') ? '&'.$data : '?'.$data;
            curl_setopt($ch,CURLOPT_HTTPGET,1);
        }
    }
    curl_setopt($ch,CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_REFERER, $referer ?? "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    curl_setopt($ch,CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11');
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

    ob_start();
    curl_exec($ch);
    $contents = ob_get_contents();
    ob_end_clean();
    curl_close($ch);

    return $contents;
}

/**
 * @param $url
 * @param $data
 * @param int $timeout
 * @param $referer
 * @return false|string
 */
/* get请求 */
function httpGet($url, $data = null, int $timeout=5, $referer=null): bool|string
{
    return httpRequest($url, $data, 'GET', $timeout, $referer);
}

/**
 * @param $url
 * @param $data
 * @param int $timeout
 * @param $referer
 * @return false|string
 */
function httpPost($url, $data = null, int $timeout=5, $referer=null): bool|string
{
    return httpRequest($url, $data, 'POST', $timeout, $referer);

}

/**
 * 数组 转 对象
 *
 * @param array $arr 数组
 * @return object
 */
function array_to_object($arr) {
    if (gettype($arr) != 'array') {
        return;
    }
    foreach ($arr as $k => $v) {
        if (gettype($v) == 'array' || getType($v) == 'object') {
            $arr[$k] = (object)array_to_object($v);
        }
    }
    return (object)$arr;
}

/**
 * 对象 转 数组
 *
 * @param object $obj 对象
 * @return array
 */
function object_to_array($obj) {
    $obj = (array)$obj;
    foreach ($obj as $k => $v) {
        if (gettype($v) == 'resource') {
            return;
        }
        if (gettype($v) == 'object' || gettype($v) == 'array') {
            $obj[$k] = (array)object_to_array($v);
        }
    }
    return $obj;
}

function base32_encode(string $input) :string {
    $BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
    $output = '';
    $v = 0;
    $vbits = 0;

    for ($i = 0, $j = strlen($input); $i < $j; $i++) {
        $v <<= 8;
        $v += ord($input[$i]);
        $vbits += 8;

        while ($vbits >= 5) {
            $vbits -= 5;
            $output .= $BASE32_ALPHABET[$v >> $vbits];
            $v &= ((1 << $vbits) - 1);
        }
    }

    if ($vbits > 0) {
        $v <<= (5 - $vbits);
        $output .= $BASE32_ALPHABET[$v];
    }

    return $output;
}

function base32_decode(string $input) :string {
    $output = '';
    $v = 0;
    $vbits = 0;

    for ($i = 0, $j = strlen($input); $i < $j; $i++) {
        $v <<= 5;
        if ($input[$i] >= 'a' && $input[$i] <= 'z') {
            $v += (ord($input[$i]) - 97);
        } elseif ($input[$i] >= '2' && $input[$i] <= '7') {
            $v += (24 + $input[$i]);
        } else {
            return '';
        }

        $vbits += 5;
        while ($vbits >= 8) {
            $vbits -= 8;
            $output .= chr($v >> $vbits);
            $v &= ((1 << $vbits) - 1);
        }
    }
    return $output;
}

function aesEncode($data){
    $method = "AES-256-CBC";
    return  base64_encode(openssl_encrypt($data, $method, ENCRYPT_KEY, OPENSSL_RAW_DATA , ENCRYPT_IV));
}

function aesDecode($data){
    $method = "AES-256-CBC";
    return openssl_decrypt(base64_decode($data),  $method, ENCRYPT_KEY, OPENSSL_RAW_DATA, ENCRYPT_IV);
}

/**
 * 对一个二维数组进行加工, 使其成为一个按照key进行索引的一个数组
 * @param $arr
 * @param $key
 * @return array
 */
function array_index_by_key($arr, $key){
    $d = [];
    foreach ($arr as $a) {
        if(is_array($a) && isset($a[$key])){
            $d[$a[$key]] = $a;
        }
    }
    return $d;
}

/**
 * 对数组进行递归排序
 * @param $array
 * @return bool
 */
function ksortRecursive(&$array): bool
{
    if (!is_array($array)) {
        return false;
    }
    foreach ($array as $key => &$value) {
        if (is_array($value)) {
            ksortRecursive($value); // 对子数组进行排序
        }
    }
    ksort($array); // 对当前数组进行排序
    return true;
}


/**
 * 拼接数组的值为一个字符串
 * @param $array
 * @param $separator
 * @return string
 */
function arrayToString($array, $separator = '_crypt_'): string
{
    $result = '';

    // 遍历数组，对每个元素进行处理
    foreach ($array as $value) {
        // 如果是数组，递归调用该函数
        if (is_array($value)) {
            $value = arrayToString($value, $separator);
        }
        // 添加元素到结果字符串，并在每个元素之后添加分隔符
        $result .= $value . $separator;
    }

    // 删除最后的分隔符
    if ($separator && !empty($result)) {
        $result = rtrim($result, $separator);
    }

    return $result;
}